#include "ProductionParser.h"
#include <cctype>
#include <vector>
#include "wfx.h"
#include "ErrorHandle.h"

using namespace std;

char EscapeCode(char code)
{
    switch (code)
    {
    case '0' :
        return '\0';
    case '"' :
        return '\"';
    case '\\' :
        return '\\';
    case 'r' :
        return '\r';
    case 'n' :
        return '\n';
    case 't' :
        return '\t';
    default:
        throw production_exception() << error_message("unknown escape code");
        return '\0';
    }
}

std::vector<Token_Type> CProductionParser::Parse( std::string production )
{
    vector<Token_Type> vec;
    bool Escaped = false;
    bool Reading_NonTerminate = false;
    bool Reading_SpetialToken_KeyWord = false;
    bool LeftPartFinished = false;


    string part;
    for (int charIndex = 0; charIndex != production.length(); ++charIndex)
    {
        Escaped = false;
        char currentChar = production[charIndex];

        // if we are reading the content 
        // deal with the escape code
        if (Reading_NonTerminate || Reading_SpetialToken_KeyWord)
        {
            if (currentChar == '\\')
            {
                if (charIndex + 1 != production.length())
                {
                    Escaped = true;
                    char nextChar = production[++charIndex];

                    try
                    {
                        currentChar = EscapeCode(nextChar);
                    }
                    catch (production_exception& e)
                    {
                        e   << current_char_count(charIndex)
                            << current_char(nextChar);
                        throw e;
                    }


                    currentChar = EscapeCode(nextChar);

                }
            }
        }



        if (Reading_NonTerminate) // Reading the Nontermiante_Token
        {
            if (currentChar == '>')
            {
                Reading_NonTerminate = false;

                if (!part.empty())
                {
                    vec.push_back(CTokenManager::Instance()->NonterminateToken(part));
                }
                else
                {
                    throw production_exception() 
                        << error_message("empty token id is not allowed")
                        << current_char_count(charIndex)
                        << current_char(currentChar);
                }

                part.clear();
                continue;
            }
            else
            {
                part.append(1,currentChar);
            }
        }
        else if (Reading_SpetialToken_KeyWord)
        {
            if (currentChar == ']')
            {
                Reading_SpetialToken_KeyWord = false;
                if (!part.empty())
                {
                    if (isalpha(part[0]))
                    {
                        vec.push_back(CTokenManager::Instance()->Keyword(part));
                    }
                    else
                    {
                        vec.push_back(CTokenManager::Instance()->SpecialToken(part));
                    }
                }
                else
                {
                    throw production_exception() 
                        << error_message("empty token id is not allowed")
                        << current_char_count(charIndex)
                        << current_char(currentChar);
                }


                

                part.clear();
                continue;
            }
            else
            {
                part.append(1,currentChar);
            }
        }
        else
        {

            if (isspace(currentChar))
            {
                continue;
            }
            else if (currentChar == '<')
            {
                Reading_NonTerminate = true;
            }
            else if (currentChar == '[')
            {
                Reading_SpetialToken_KeyWord = true;
            }
            else if (currentChar == '-') // reading the "->"
            {
                if (charIndex + 1 != production.length())
                {
                    ++charIndex;
                    if (production[charIndex] == '>')
                    {
                        if (vec.size() == 1)
                        {
                            LeftPartFinished = true;
                            continue;
                        }
                        else
                        {
                            throw production_exception() 
                                << error_message("there should be only one nonterminate on the left of a production")
                                << current_char_count(charIndex)
                                << current_char(currentChar);
                        }

                    }
                    else
                    {
                        throw production_exception() 
                            << error_message("unsuitable character")
                            << current_char_count(charIndex)
                            << current_char(currentChar);
                    }
                }
            }
            else
            {
                throw production_exception() 
                    << error_message("unsuitable character")
                    << current_char_count(charIndex)
                    << current_char(currentChar);
            }

        }

    }
    
    // when the string is finished
    if (Reading_NonTerminate || Reading_SpetialToken_KeyWord)
    {
        throw production_exception() 
            << error_message("unexpected end of production");
    }

    if (!LeftPartFinished || vec.size() < 2)
    {
        throw production_exception() 
            << error_message("wrong production format");
    }

    return vec;
}